package org.iabako.server.serviceimpl.function;

import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.iabako.server.dao.business.CustomFieldDAO;
import org.iabako.server.dao.business.QueryDefinitionDAO;
import org.iabako.server.serviceimpl.security.SessionUser;
import org.iabako.server.tools.BundleMessages;
import org.iabako.server.tools.IabakoWorkbook;
import org.iabako.shared.entity.business.CustomField;
import org.iabako.shared.entity.business.CustomFieldValue;
import org.iabako.shared.entity.enumeration.ImageEnum;
import org.iabako.shared.entity.enumeration.LabelEnum;
import org.iabako.shared.iservice.function.ExcelGeneratorService;
import org.iabako.shared.querydefinition.columndefinition.ClientColumnEnum;
import org.iabako.shared.querydefinition.columndefinition.ColumnDefinition;
import org.iabako.shared.querydefinition.columndefinition.PastInstallmentColumnEnum;
import org.iabako.shared.querydefinition.columndefinition.SaleColumnEnum;
import org.iabako.shared.querydefinition.dto.*;
import org.iabako.shared.tools.GenericTools;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by jose on 15/09/14.
 */

@org.springframework.stereotype.Service("excelService")
public class ExcelGeneratorServiceImpl implements ExcelGeneratorService {

    static Logger log = Logger.getLogger(ExcelGeneratorServiceImpl.class.getName());

    @Autowired
    QueryDefinitionDAO queryDefinitionDAO;
    @Autowired
    CustomFieldDAO customFieldDAO;
    @Autowired
    BundleMessages messages;
    @Autowired
    SessionUser userComponent;

    public synchronized String getExcelFile(QueryDefinitionDTO queryDefinitionDTO) {

        //if queryDefinition was affected by customModification (ex. add transient columns in sale tables)
        //complete search without limits (min, max) has to be managed in client side (even if it's more expensive)
        if (!queryDefinitionDTO.isCustomModifications()) {
            queryDefinitionDTO.setPageSize(-1);
            queryDefinitionDAO.executeQueryDefinition(queryDefinitionDTO);
        }

        ColumnDefinition clientNumberColumn = null;
        Map<String, Map<CustomField, CustomFieldValue>> customFieldValues = null;
        String clientNumber = null;

        for (ColumnDefinition columnDefinition : queryDefinitionDTO.getSearchMotorQuery().getColumns()) {
            if (columnDefinition == ClientColumnEnum.number
                    || columnDefinition == SaleColumnEnum.clientNumber
                    || columnDefinition == PastInstallmentColumnEnum.clientNumber) {
                clientNumberColumn = columnDefinition;
                break;
            }
        }

        if (clientNumberColumn != null) {
            List<String> clientNumbers = new ArrayList<String>();
            for (QueryResultDTO result : queryDefinitionDTO.getResults().values()) {
                clientNumber = (String) result.getValues().get(clientNumberColumn).getValue();
                if (clientNumber != null) {
                    clientNumbers.add(clientNumber);
                }
            }
            customFieldValues = customFieldDAO.getCustomFieldValues(clientNumbers);
        }

        boolean customClientColumnsPresent = clientNumberColumn != null && !GenericTools.isEmpty(customFieldValues);

        String fileName = messages.getLabel(queryDefinitionDTO.getSearchMotorQuery().getExportFileName());

        IabakoWorkbook iabakoWorkbook = new IabakoWorkbook(fileName, fileName, userComponent.getUser().getEnterprise().getName());

        Sheet sheet = iabakoWorkbook.getSheets().get(0);
        Map<String, CellStyle> styles = iabakoWorkbook.getStyles();

        //header row
        int indexColumns;

        for (indexColumns = 0; indexColumns < queryDefinitionDTO.getSearchMotorQuery().getColumns().length; indexColumns++) {
            //columns width
            ColumnDefinition columnDefinition = queryDefinitionDTO.getSearchMotorQuery().getColumns()[indexColumns];

            iabakoWorkbook.addHeaderDefinition(columnDefinition.getExcelColumnWidth(),
                    messages.getLabel(queryDefinitionDTO.getSearchMotorQuery().getColumns()[indexColumns].getLabelKey()));
        }

        //custom headers
        if (customClientColumnsPresent) {
            for (Map<CustomField, CustomFieldValue> customColumns : customFieldValues.values()) {
                for (CustomField customField : customColumns.keySet()) {
                    iabakoWorkbook.addHeaderDefinition(3000, customField.getTitle());
                }
                break;
            }
        }

        iabakoWorkbook.addHeader(sheet, false, 0);

        //content
        int rowNum = 1;
        for (Long keyRow : queryDefinitionDTO.getResults().keySet()) {
            Row row = sheet.createRow(rowNum++);
            row.setHeightInPoints(25);
            int j = 0;
            QueryResultDTO result = queryDefinitionDTO.getResults().get(keyRow);
            for (ColumnDefinition columnDefinition : result.getValues().keySet()) {

                QueryResultValue queryResultValue = result.getValues().get(columnDefinition);
                Object value = queryResultValue != null ? queryResultValue.getValue() : null;

                Cell cell = row.createCell(j++);

                fillCell(iabakoWorkbook, cell, columnDefinition.getClassName() != null
                        && columnDefinition.getClassName().contains("columncenteralign") ?
                        styles.get("cellCenter") : null, columnDefinition, value);
            }

            if (!customClientColumnsPresent) {
                continue;
            }

            clientNumber = (String) result.getValues().get(clientNumberColumn).getValue();

            // customClientColumnsPresent but CustomFields empty for this client
            if (customFieldValues.get(clientNumber) == null) {
                for (Map<CustomField, CustomFieldValue> customColumns : customFieldValues.values()) {
                    for (int k = 0; k < customColumns.keySet().size(); k++) {
                        Cell cell = row.createCell(j++);
                        fillCell(iabakoWorkbook, cell, null, null, null);
                    }
                    break;
                }
                continue;
            }

            // CustomFields
            for (CustomFieldValue customFieldValue : customFieldValues.get(clientNumber).values()) {
                Cell cell = row.createCell(j++);
                fillCell(iabakoWorkbook, cell, null, null, customFieldValue != null ? customFieldValue.getValue() : null);
            }
        }

        return iabakoWorkbook.addFileToSession();
    }

    private void fillCell(IabakoWorkbook iabakoWorkbook, Cell cell, CellStyle cellStyle, ColumnDefinition columnDefinition, Object value) {

        if (columnDefinition != null && columnDefinition.getQueryResultValueType() == QueryResultValueType.LONG && value == null) {
            value = 0L;
        } else if (columnDefinition != null &&
                (columnDefinition.getQueryResultValueType() == QueryResultValueType.DOUBLE || columnDefinition.getQueryResultValueType() == QueryResultValueType.LONG_DOUBLE)
                && value == null) {
            value = 0D;
        }

        if (value instanceof Enum) {
            cellStyle = iabakoWorkbook.getStyles().get("cell");
            if (value instanceof ImageEnum) {
                value = messages.getLabel(((ImageEnum) value).getTitleKey());
            } else if (value instanceof LabelEnum) {
                value = messages.getLabel(((LabelEnum) value).getLabelKey());
            }
        } else if (value instanceof IconValue) {
            cellStyle = iabakoWorkbook.getStyles().get("cell");
            value = ((IconValue) value).getText();
        } else if (value instanceof Boolean) {
            cellStyle = iabakoWorkbook.getStyles().get("cell");
            value = (Boolean) value ? messages.getLabel("yes") : messages.getLabel("no");
        }

        iabakoWorkbook.fillCell(cell, cellStyle, value);
    }
}
